iT邦幫忙

2022 iThome 鐵人賽

DAY 24
1

Proxy 字面上是「代理」的意思,意味著當我們要做去做一些事情前,會先透過代理的這一層,之後才交給真正的物件做處理。我們在現實生活中,就有蠻多會遇到 Proxy 的例子,例如當雙十一時,每個人都在店商網站上瘋狂購物,對於後端伺服器的請求量就會相當大,這時候就可以使用Proxy。

當使用者發送請求後,他會先呼叫到的是一個代理伺服器,這邊會去判斷說他要做的操作,再決定是否要真正將請求再丟給真實伺服器去處理。我們以今天的例子來看,如果請求是成功的,那我就會做紀錄,下次有同樣請求再來時,我就直接將結果回傳,就不用再丟給後端伺服器,也就能夠減少後端伺服器的資料處理量以及負擔。

Proxy - 定義

爲其他物件提供一種代理以控制對這個物件的訪問。

https://ithelp.ithome.com.tw/upload/images/20221002/20136443pmxtXFhVjL.png

(圖片來源:https://zh.wikipedia.org/wiki/代理模式#/media/File:Proxy_pattern_diagram.svg)

範例 UML

https://ithelp.ithome.com.tw/upload/images/20221002/20136443U094kpDcH3.png

Code要點

  • IHandlerRealServer以及 ProxyServer的共通介面,會定義需要實作的方法。
  • RealServer會去資料庫取出資料(這邊用隨機 Random表示是否有成功從資料庫取出資料)。
  • ProxyServer會去呼叫RealServer,如果有從資料庫取資料成功,則將這次請求記錄起來,如果下次又有同樣的請求來時,就直接回傳結果,不再呼叫RealServer

不囉嗦上Code!

using System;
using System.Collections.Generic;

namespace DAY24_Proxy
{
    public class Program
    {
        static void Main(string[] args)
        {
            IHandler proxyServer = new ProxyServer();

            // 同樣的請求執行兩輪,如果上次請求成功,代理伺服器即直接回傳,否則呼叫真實伺服器
            for (int loop = 0; loop < 2; loop++)
            {
                for (int x = 0; x < 5; x++)
                {
                    proxyServer.HandleRequest($"請求{x}");
                }
            }

        }
    }

    // 定義共通介面
    public interface IHandler
    {
        bool HandleRequest(string request);
    }

    public class RealServer : IHandler
    {
        // 實作介面,並從資庫取資料
        public bool HandleRequest(string request)
        {
            Console.WriteLine($"{request},開始處理");
            return GetDataFromDatabase(request);
        }

        private bool GetDataFromDatabase(string request)
        {
            bool result;
            Random rnd = new Random();
            var isSuccess = rnd.Next(10)%2 == 0;
            if (isSuccess)
            {
                Console.WriteLine($"{request} => 從資料庫取出資料成功!\n");
                result =  true;
            }
            else
            {
                Console.WriteLine($"{request} => 從資料庫取出資料失敗!\n");
                result = false;
            }
            return result;
        }
    }

    public class ProxyServer : IHandler
    {
        private readonly List<string> _requestLists;
        private readonly RealServer _realServer;

        public ProxyServer()
        {
            _realServer = new RealServer();
            _requestLists = new List<string>();
        }

        public bool HandleRequest(string request)
        {
            bool result;
            // 代理伺服器會先尋找同樣請求之前是否有成功,有則直接回傳true,沒有則呼叫真實伺服器
            if (_requestLists.Contains(request)) {
                Console.WriteLine($"{request}已有紀錄,直接回傳成功!\n");
                result = true;
            }
            else
            {
                // 如果請求成功,代理伺服器會將請求字串存入List,以便下次再來同個請求即可直接回傳true
                result = _realServer.HandleRequest(request);
                if (result) _requestLists.Add(request);
            }
            return result;
        }
    }
}
  • 結果

https://ithelp.ithome.com.tw/upload/images/20221002/20136443U4KAyxG3DE.png

簡單的小結

透過 Proxy 模式,我們可以先在代理部分做判斷,再去呼叫真實物件做處理,這樣用代理伺服器的好處除了能減少後端的負擔,同時我們也能夠在代理伺服器就先過濾掉可能的危險請求,以保證送去後端的請求是安全的。當然上面例子只是代理模式的其中一種應用,還有很多像是防火牆或是虛擬代理人等等的模式應用,這部分未來有機會再做成一篇文章跟大家介紹。


上一篇
【DAY23】Flyweight模式 - 共享的意義
下一篇
【DAY25】Memento模式 - 無限生命值的秘訣!
系列文
勇闖秘境!探索物件導向背後的設計模式30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言